/**
 * Copyright (C) 2011 Domenico Briganti <dometec@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package it.webrules.deploymanager.webapp.service;

import it.webrules.deploymanager.webapp.OperationDescription;
import it.webrules.deploymanager.webapp.controller.ConfigTreeController;
import it.webrules.deploymanager.webapp.exception.AlreadyExistException;
import it.webrules.deploymanager.webapp.exception.NotCreatedException;
import it.webrules.deploymanager.webapp.exception.NotDeletedException;
import it.webrules.deploymanager.webapp.service.persistence.StorageSystem;
import it.webrules.deploymanager.webapp.transentities.CType;
import it.webrules.deploymanager.webapp.transentities.ConfigEntry;
import it.webrules.deploymanager.webapp.transentities.ConfigPath;
import it.webrules.deploymanager.webapp.utils.FileUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;

import com.google.inject.Inject;

@Singleton
public class ConfigurationService extends BaseService {

	@Inject
	private StorageSystem storageSystem;

	public ConfigurationService() {
		logger.info("Inizialization of {}.", this.getClass().getName());
	}

	public File getFileFromPath(String path) {
		File file = new File(storageSystem.getConfigRoot().getPath() + File.separator + path);
		return file;
	}

	public ConfigPath getConfig(String path, UriBuilder baseUriBuilder) throws FileNotFoundException {

		if (path == null)
			path = "";

		File configpath = getFileFromPath(path);

		if (!configpath.exists())
			throw new FileNotFoundException();

		if (configpath.isDirectory())
			return getConfig(path, configpath, baseUriBuilder.clone());

		return null;

	}

	public void createPath(String path) throws NotCreatedException, AlreadyExistException {

		File pathFile = getFileFromPath(path);
		if (pathFile.exists())
			throw new AlreadyExistException();

		if (!pathFile.mkdir())
			throw new NotCreatedException();

	}

	public void delete(String path) throws FileNotFoundException, NotDeletedException {

		File pathFile = getFileFromPath(path);
		if (!pathFile.exists())
			throw new FileNotFoundException();

		if (pathFile.delete())
			throw new NotDeletedException();

	}

	public void createConfiguration(String path, InputStream in) throws AlreadyExistException, IOException {

		File pathFile = getFileFromPath(path);

		if (pathFile.exists())
			throw new AlreadyExistException();

		try (FileOutputStream out = new FileOutputStream(pathFile, false)) {
			FileUtils.inputStreamToOutputStream(in, out);
		} catch (IOException e) {
			throw e;
		}

	}

	public void updateConfiguration(String path, InputStream in) throws AlreadyExistException, IOException {

		File pathFile = getFileFromPath(path);

		if (!pathFile.exists())
			throw new FileNotFoundException();

		try (FileOutputStream out = new FileOutputStream(pathFile, false)) {
			FileUtils.inputStreamToOutputStream(in, out);
		} catch (IOException e) {
			throw e;
		}

	}

	public ConfigPath getConfig(String path, File configdir, UriBuilder baseUriBuilder) {

		String spath = path;
		if (path.length() > 0)
			spath = "/" + path;

		ConfigPath configPath = new ConfigPath();
		configPath.name = path.substring(path.lastIndexOf("/") + 1);
		configPath.path = baseUriBuilder.clone().path(ConfigTreeController.class).build(spath);

		String[] subdir = configdir.list(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				return new File(dir + File.separator + name).isDirectory();
			}
		});

		List<ConfigPath> subdirs = new ArrayList<>();
		for (String dir : subdir) {
			ConfigPath p = new ConfigPath();
			p.name = dir;
			p.path = baseUriBuilder.clone().path(ConfigTreeController.class).build(spath + "/" + dir);
			subdirs.add(p);
		}

		if (subdirs.size() > 0)
			configPath.childs = subdirs.toArray(new ConfigPath[] {});

		String[] configChild = configdir.list(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				return !new File(dir + File.separator + name).isDirectory();
			}
		});

		List<ConfigEntry> configurationChilds = appendConfigurationChilds(path, configChild, baseUriBuilder);
		if (configurationChilds.size() > 0)
			configPath.configs = configurationChilds.toArray(new ConfigEntry[] {});

		return configPath;
	}

	/**
	 * For eache child of this config path (eg: for each config file) append operation that can be execute 
	 * @param path
	 * @param configChild
	 * @param baseUriBuilder
	 * @return
	 */
	private List<ConfigEntry> appendConfigurationChilds(String path, String[] configChild, UriBuilder baseUriBuilder) {

		List<ConfigEntry> entries = new ArrayList<>();

		try {
			for (int i = 0; i < configChild.length; i++)
				entries.add(createConfigChild(path, configChild[i], baseUriBuilder));
		} catch (NoSuchMethodException e) {
			logger.error("Method not implemented!", e);
		}

		return entries;

	}

	/**
	 * Create a ConfigEntry operation for a config file 
	 * 
	 * @param configChild
	 * @param uriBuilder
	 * @return
	 */
	private ConfigEntry createConfigChild(String path, String filename, UriBuilder baseUriBuilder) throws NoSuchMethodException {

		ConfigEntry entry = new ConfigEntry(filename);
		entry.path = baseUriBuilder.clone().path(ConfigTreeController.class).build("/" + path + "/" + filename);

		OperationDescription odesc = new OperationDescription(baseUriBuilder.clone(), path, filename);

		if (filename.endsWith("dms")) {
			entry.type = CType.staticpart;
			entry.operations = odesc.getStaticOperation();
		} else if (filename.endsWith("dmw")) {
			entry.type = CType.dinamycpart;
			entry.operations = odesc.getDinamycOperation();
		} else
			entry.type = CType.unknown;

		return entry;
	}
}
